-- Get Sol library
local Sol = LibStub("Sol");

-- Addon namespace
local PKWarning = {};
_G["PKWarning"] = PKWarning;

-- Warning frame
local PKWarningFrame;

-- Important addon vars
PKWarning.Timer = 1;
PKWarning.PKCount = 0;
PKWarning.LastWarningTime = 0;
PKWarning.ChannelNumber = 0;
PKWarning.ChannelName = "PKWarning";
PKWarning.SleepTime = 0;
PKWarning.SleepAction = "JOIN";
PKWarning.SerialPattern = "(.+):(.+):(.+):(.+):(.+):(%d+):(%d+):(.+):(.+)";

-- Settings
g_PKWarningSettings = {}
g_PKWarningBlacklist = {}

-- Frame vars
PKWarning.Frame = {};
PKWarning.Frame.PKList = {};
PKWarning.Frame.ListMax = 14;
PKWarning.Frame.NewWarnings = 0;
PKWarning.Frame.ScrollValue = 0;
PKWarning.Frame.Sort = "TIME_SEEN";
PKWarning.Frame.Channel = "-";
PKWarning.Frame.Zone = "-";

PKWarning.Config = {};
PKWarning.Config.MaxTabs = 2;
PKWarning.Config.ScrollValue = 0;
PKWarning.Config.BlacklistMax = 6;


-- Warnings table - detailed structure:
-- warnings     ["NAME"]            Name of PK
--              ["CHANNEL"]         PK's world (channel)
--              ["ZONE"]            Zone
--              ["CLASS_MAIN"]      Main class of PK
--              ["CLASS_SEC"]       Sec class of PK
--              ["LEVEL_MAIN"]      Level of PK main class
--              ["LEVEL_SEC"]       Level of PK sec class
--              ["TIME_SEEN"]       Time PK Was seen
--              ["WORLD_X"]         X coordinate of player who seen him on world map
--              ["WORLD_Y"]         Y coordinate of player who seen him on world map

PKWarning.PKs = {}; 
PKWarning.ZonePKs = {};

PKWarning.addon = {
	name = "Vlocka's PK Warning system",
	shortName = "PKWarning",
	version = "v0.5.5",
	author = "Vlocka",
	slashCommand = "/pkw",
}

function PKWarning:PKIndex(name)

    for index, pkInfo in ipairs(PKWarning.PKs) do
        if pkInfo["NAME"] == name then
            return index;
        end
    end
    
    return 0;
end

function PKWarning:InitSettings()

    if g_PKWarningSettings["ENABLE_SEND"] == nil then
        g_PKWarningSettings["ENABLE_SEND"] = true;
    end
    
    if g_PKWarningSettings["ENABLE_PARTY"] == nil then
        g_PKWarningSettings["ENABLE_PARTY"] = true;
    end

    if g_PKWarningSettings["ENABLE_SELF"] == nil then
        g_PKWarningSettings["ENABLE_SELF"] = false;
    end

    if g_PKWarningSettings["ENABLE_RECIEVE"] == nil then
        g_PKWarningSettings["ENABLE_RECIEVE"] = true;
    end

    if g_PKWarningSettings["ENABLE_ZONE_WARNING"] == nil then
        g_PKWarningSettings["ENABLE_ZONE_WARNING"] = true;
    end
    
    if g_PKWarningSettings["DISABLE_CHAT_POPUP"] == nil then
        g_PKWarningSettings["DISABLE_CHAT_POPUP"] = true;
    end
        
    -- disable chat popup
    MSN_INFO["CHANNEL"].auto = not g_PKWarningSettings["DISABLE_CHAT_POPUP"];
end

function PKWarning:OnLoad(self)
	
    PKWarningFrame = self;
    PKWarningFrame:RegisterEvent("VARIABLES_LOADED");
    PKWarningFrame:RegisterEvent("UNIT_TARGET_CHANGED");
    PKWarningFrame:RegisterEvent("CHAT_MSG_CHANNEL");
    PKWarningFrame:RegisterEvent("CHAT_MSG_SYSTEM");
    PKWarningFrame:RegisterEvent("ZONE_CHANGED");
	        
end

function PKWarning:OnShow(this)
    if (g_PKWarningSettings["BUT_X"] ~= nil and g_PKWarningSettings["BUT_Y"] ~= nil) then
        this:ClearAllAnchors();
        this:SetAnchor("TOPLEFT", "TOPLEFT", UIParent, g_PKWarningSettings["BUT_X"], g_PKWarningSettings["BUT_Y"]);
    end
end

function PKWarning:OnEvent(self, event, arg1, arg2, arg3, arg4)

    if (event == "VARIABLES_LOADED") then

        -- If not loaded settings, set them to default value
        PKWarning:InitSettings();

        -- Register slash command
        Sol.config.CreateSlashToHandleConfig("PKWarning", PKWarningConfig, "pkw");

        -- Load locale strings
        local locale_client = GetLocation():sub(1,2);
        Sol.util.LoadFile("PKWarning/Locales/" .. locale_client .. ".lua");
                
        -- Play with the AddonManager, if exists
        if AddonManager then
            local addon = {
                name = PKWarning.addon.name, 
                description = PKWarning.Lang.Strings["DESCRIPTION"], 
                category = "PvP",
                slashCommand = PKWarning.addon.slashCommand, 
                version = PKWarning.addon.version,
                author = PKWarning.addon.author,
            }
            if AddonManager.RegisterAddonTable then
                AddonManager.RegisterAddonTable(addon);
            else
                AddonManager.RegisterAddon(
                    addon.name, 
                    addon.description, 
                    addon.icon, 
                    addon.category,
                    PKWarningConfig, 
                    addon.slashCommand,
                    addon.miniButton, 
                    PKWarningConfig_Toggle,
                    addon.version, 
                    addon.author
                );
            end
        else
            DEFAULT_CHAT_FRAME:AddMessage("|cffff0000" .. PKWarning.addon.name .. "|r |cffff0000" .. PKWarning.addon.version .. PKWarning.Lang.Strings["ADDON_LOADED"]);
        end        
                
        -- Save settings
        SaveVariables("g_PKWarningSettings");
        SaveVariables("g_PKWarningBlacklist");
        
        -- Manage channel
        PKWarning:Debug("Connecting to PKWarning channel in 3 seconds..");
        PKWarning.SleepTime = 5;
        
    ------------------------------------------------------------------
    -- Target change event                                      ------
    -- check if target is PK and if it's not you, send warning  ------
    ------------------------------------------------------------------
    elseif (event == "UNIT_TARGET_CHANGED") then
    
        if (UnitIsPlayer("target")) then
            PKWarning:SendWarning();
        end
        
    ------------------------------------------------------------------
    -- System messages                                         -------
    -- Create channel if recieved a system error about joining -------
    ------------------------------------------------------------------
    elseif (event == "CHAT_MSG_SYSTEM") then
    
        PKWarning:Debug("System message recieved: " .. arg1);
        
        if arg1 == string.gsub(PKWarning.Lang.Strings["SYS_JOIN_FAILED"], "<channel>", PKWarning.ChannelName) then
            PKWarning.SleepTime = 3;
            PKWarning.SleepAction = "CREATE";
        elseif arg1 == string.gsub(PKWarning.Lang.Strings["SYS_CREATE_FAILED"], "<channel>", PKWarning.ChannelName) then
            PKWarning.SleepTime = 3;
            PKWarning.SleepAction = "JOIN";        
        end 
        
    ------------------------------------------------------------------
    -- Chat private channel messages                                --
    -- Listen for meesages about joining channel and if joined      --
    -- PKWarning channel, then hide it and store it's number        --
    ------------------------------------------------------------------
    elseif (event == "CHAT_MSG_CHANNEL") then
    
        if GetChannelName(arg3) == PKWarning.ChannelName then
        
            if DEFAULT_CHAT_FRAME.channelList[arg3] ~= nil then
                DEFAULT_CHAT_FRAME.channelList[arg3] = nil;
            end
        
            -- Player joins channel
            if Sol.string.EndsWith(arg1, PKWarning.Lang.Strings["CHANNEL_JOIN"]) then
                                
                if UnitName("player") == nil or Sol.string.StartsWith(arg1, UnitName("player")) then
                    PKWarning.ChannelNumber = arg3;
                    PKWarning.SleepTime = 0;
                    SendSystemChat(string.gsub(PKWarning.Lang.Strings["MSG_JOIN"], "<channelnum>", PKWarning.ChannelNumber));
                end
                
            -- Player disconnects
            elseif Sol.string.EndsWith(arg1, PKWarning.Lang.Strings["CHANNEL_LEAVE"]) then
            
                if Sol.string.StartsWith(arg1, UnitName("player")) then
                    PKWarning.ChannelNumber = 0;
                    SendSystemChat(PKWarning.Lang.Strings["MSG_LEAVE"]);
                end
                
            end
        
            ----------------------------------------
            -- Message from PKWarning channel ------
            ----------------------------------------
            PKWarning:ParseMessage(arg1);        
        end
            
    elseif (event == "ZONE_CHANGED") then
        
        PKWarning:ShowZoneInfo();
    end 
    
           
end 

--------------------------------------------------------------------------------
-- Function called when updating frame  ----------------------------------------
--------------------------------------------------------------------------------
function PKWarning:OnUpdate(this, elapsedTime)

    -- Take elapsed time from timer
    PKWarning.Timer = PKWarning.Timer - elapsedTime;
    
    -- 1 Second elapsed
    if PKWarning.Timer < 0 then

        -- Refresh timer to 1 second
        PKWarning.Timer = 1;

        -- Time to join/create channel!
        if PKWarning.SleepTime == 1 then
            PKWarning.SleepTime = 0;
            
            if PKWarning.SleepAction == "JOIN" then
                JoinChannel(PKWarning.ChannelName);
            else
                CreateChannel(PKWarning.ChannelName);
            end
            
        -- Countdown
        elseif PKWarning.SleepTime > 1 then
            PKWarning:Debug(PKWarning.SleepTime .. " seconds to connect");
            PKWarning.SleepTime = PKWarning.SleepTime - 1;            
        end
    
        ---------------------------------------------
        --- Check for old warnings and remove them
        ---------------------------------------------
        local timeNow = math.floor(GetTime());
        
        for pkIndex, pkInfo in ipairs(PKWarning.PKs) do
        
            if (timeNow - pkInfo["TIME_SEEN"]) > 360 then
                
                if not Sol.table.Contains(g_PKWarningBlacklist, pkInfo["ZONE"]) then
                    PKWarning:RecountPKs();
                end
                
                table.remove(PKWarning.PKs, pkIndex);
                PKWarning:UpdateZoneList();
                PKWarning:UpdateIcon();
            end            
        end
        
        ---------------------------------------------
        --- Refresh window if shown -----------------
        ---------------------------------------------
        if PKWarningPanelFrame:IsVisible() then
            PKWarning:InitList();
        end
    end

end

-------------------------------------------------------
-- Parses a message recieved from PKWarning channel ---
-- adds a data to your DB and refreshes warnings    ---
-------------------------------------------------------
function PKWarning:ParseMessage(serial)

    -- If recieving disabled
    if not g_PKWarningSettings["ENABLE_RECIEVE"] then
        return
    end

    if serial:find(PKWarning.SerialPattern) then
    
        local dummy1, dummy2, pkName, pkChannel, pkZone, pkClass1, pkClass2, pkLvl1, pkLvl2, posX, posY = serial:find(PKWarning.SerialPattern);
    
        --PKWarning:Debug(serial);

        local pkInfo = {};
        local pkIndex = PKWarning:PKIndex(pkName);
    
        pkInfo["NAME"] = pkName;
        pkInfo["CHANNEL"] = pkChannel;
        pkInfo["ZONE"] = pkZone;
        pkInfo["CLASS_MAIN"] = pkClass1;
        pkInfo["CLASS_SEC"] = pkClass2;
        pkInfo["LEVEL_MAIN"] = pkLvl1;
        pkInfo["LEVEL_SEC"] = pkLvl2;
        pkInfo["TIME_SEEN"] = math.floor(GetTime());
        pkInfo["WORLD_X"] = posX;
        pkInfo["WORLD_Y"] = posY;
        
        -- Check for unknown classes
        if not PKWarning.Lang.Classes[pkInfo["CLASS_MAIN"]] then
            
            if PKWarning.Lang.Classes.Dictionary[pkInfo["CLASS_MAIN"]] then
                pkInfo["CLASS_MAIN"] = PKWarning.Lang.Classes.Dictionary[pkInfo["CLASS_MAIN"]];
                pkInfo["CLASS_SEC"] = PKWarning.Lang.Classes.Dictionary[pkInfo["CLASS_SEC"]];
            else
                pkInfo["CLASS_MAIN"] = PKWarning.Lang.Strings["UNKNOWN"];
                pkInfo["CLASS_SEC"] = PKWarning.Lang.Strings["UNKNOWN"];
            end 
        end 

        -- If PK is not in my list
        if pkIndex == 0 then
        
            table.insert(PKWarning.PKs, pkInfo);
            
            -- Increment number of new warnings
            if not Sol.table.Contains(g_PKWarningBlacklist, pkZone) then
                PKWarning.Frame.NewWarnings = PKWarning.Frame.NewWarnings + 1;
                PKWarning:RecountPKs();
            end
            
        -- Else update info
        else
            PKWarning.PKs[pkIndex] = pkInfo;
        end
        
        PKWarning:SortList();
        PKWarning:UpdateZoneList();
    
    end
end

-------------------------------------------------------------
-- Prints debug messages to chat window, if DEBUG enabled ---
-------------------------------------------------------------
function PKWarning:Debug(string)
    --DEFAULT_CHAT_FRAME:AddMessage(string);
end

--------------------------------------------------------------
-- Function called after stopped moving with PK list frame  --
-- saves a position                                         --
--------------------------------------------------------------
function PKWarning:StopFrameMoving(this, key)

    this:StopMovingOrSizing();
  
    local x, y = this:GetPos();
    local scale = this:GetRealScale();
  
    g_PKWarningSettings["BUT_X"] = x / scale;
    g_PKWarningSettings["BUT_Y"] = y / scale;
end

--------------------------------------------------------------------------------
-- Send warning to shared channel, including target's channel, zone name,   ----
-- target name, classes, levels and near position                           ----
--------------------------------------------------------------------------------
function PKWarning:SendWarning()

    -- Do NOT send anything if sendning turned off in config
    if not g_PKWarningSettings["ENABLE_SEND"] then
        return;
    end
    
    -- Stop spamming (Multiple same messages when targeting)
    local timeNow = GetTime();
    if (timeNow - PKWarning.LastWarningTime) < 1 then
        return
    end    
    
    local pkName = UnitName("target");
    
    -- Do nothing if not connected
    if PKWarning.ChannelNumber == 0 then
        return
    end

    -- Do NOT send warnings about people in party if turned off 
    if not g_PKWarningSettings["ENABLE_PARTY"] then
        
        -- Search for target in party
        local id = 1;
        while GetPartyMember(id) do
            if GetPartyMember(id) == pkName then
                return
            end
            id = id + 1;
        end 
    end

    -- Do nothing if targeting self
    if pkName == UnitName("player") then
        if not g_PKWarningSettings["ENABLE_SELF"] then
            return
        elseif not PKWarning:PlayerIsPK() then
            return
        end
        
    -- Check if target is really PK
    elseif not PKWarning:TargetIsPK() then
        return
    end
    
    -- Stop spamming (Multiple PK in a few minutes)
    -- To avoid more spamming, warning about 1 PKer can only be sent once in 8sec
    local pkIndex = PKWarning:PKIndex(pkName);       
         
    if pkIndex > 0 then
        if timeNow - PKWarning.PKs[pkIndex]["TIME_SEEN"] < 15 then
            return
        end
    end 

    local lvl1, lvl2 = UnitLevel("target");
    local class1, class2 = UnitClass("target");
    local zoneName = GetZoneName();
    local gameChannel = "" .. GetCurrentParallelID();
    local x, y = PKWarning:GetPlayerLocation();

    if not lvl2 then
        lvl2 = 0;
    end
    
    if class2 == "" then
        class2 = "-";
    end
        
    SendChatMessage(pkName .. ":" .. gameChannel .. ":" .. zoneName .. ":" .. class1 .. ":" .. class2 .. ":" .. lvl1 .. ":" .. lvl2 .. ":" .. x .. ":" .. y, "CHANNEL" , 0, PKWarning.ChannelNumber);
    PKWarning.LastWarningTime = GetTime();
end

--------------------------------------------------------------------------
-- Key function which decides if player(self) is PK or not ---------------
--------------------------------------------------------------------------
function PKWarning:PlayerIsPK()

    -- Search for self PK Mode buff
    i = 1;
    while(UnitBuff("player" , i) ~= nil) do
        if UnitBuff("player", i) == PKWarning.Lang.Strings["BUFF_PK_MODE"] then
            return true;
        end
        i = i + 1;
    end
    
    -- Search for Self Criminal debuff
    i = 1;
    while(UnitDebuff("player" , i) ~= nil) do
        if UnitDebuff("player", i) == PKWarning.Lang.Strings["DEBUFF_CRIMINAL"] then
            return true;
        end
        i = i + 1;
    end
        
    
	local rep, type = GetPlayerGoodEvil();
	
    -- If Player has negative rep.
	if rep < -30 then
	   return true;	   
	end
	
	return false;
end

--------------------------------------------------------------------------
-- Key function which decides if target is PK or not ---------------------
--------------------------------------------------------------------------
function PKWarning:TargetIsPK()

    -- Search for PK Mode buff
    local i = 1;
    while(UnitBuff("target" , i) ~= nil) do
        if UnitBuff("target", i) == PKWarning.Lang.Strings["BUFF_PK_MODE"] then
            return true;
        end
        i = i + 1;
    end

    -- Search for Criminal debuff
    i = 1;
    while(UnitDebuff("target" , i) ~= nil) do
        if UnitDebuff("target", i) == PKWarning.Lang.Strings["DEBUFF_CRIMINAL"] then
            return true;
        end
        i = i + 1;
    end
    
    -- If this function works, then return true :)
    if UnitPKState("target") then
        return true;
    end
    
    -- Search for self PK Mode buff
    i = 1;
    while(UnitBuff("player" , i) ~= nil) do
        if UnitBuff("player", i) == PKWarning.Lang.Strings["BUFF_PK_MODE"] then
            return false;
        end
        i = i + 1;
    end
    
    -- Search for Self Criminal debuff
    i = 1;
    while(UnitDebuff("player" , i) ~= nil) do
        if UnitDebuff("player", i) == PKWarning.Lang.Strings["DEBUFF_CRIMINAL"] then
            return false;
        end
        i = i + 1;
    end
        
    
	local rep, type = GetPlayerGoodEvil();
	
    -- If Player has positive (neutral) reputation and can attack target,
    -- and not in duel, target is possibly PK (or in Arena etc?)
	if rep >= -30 and UnitCanAttack("player", "target") and not PlayerDuelState() then
	   return true;
	   
    elseif rep <= -30 then
       return false;
        	
	end
end

----------------------------------------------------------------------
-- If found some PK's in your zone, prints info about them -----------
----------------------------------------------------------------------
function PKWarning:ShowZoneInfo()

    PKWarning:UpdateZoneList();
    
    if #PKWarning.ZonePKs > 0 and g_PKWarningSettings["ENABLE_ZONE_WARNING"] then 
        SendWarningMsg(string.gsub(PKWarning.Lang.Strings["ZONE_WARNING"], "<pknum>", #PKWarning.ZonePKs));
    end    
end

------------------------------------------------------------
-- Shows or hides PK Warning icon glow based on ------------
-- PK existency in current zone                 ------------
------------------------------------------------------------
function PKWarning:UpdateIcon()

    if #PKWarning.ZonePKs > 0 then
        PKWarning_IconGlow:Show();
    else
        PKWarning_IconGlow:Hide();
    end
    
    if PKWarning.Frame.NewWarnings > 0 then
        PKWarning_IconTextNew:SetText(PKWarning.Frame.NewWarnings);
        PKWarning_IconTextNew:SetColor(1, 0, 0);
    else
        PKWarning_IconTextNew:SetText("");
    end
    
    PKWarning_IconTextTotal:SetText(PKWarning.PKCount);
    
end

------------------------------------------------------------
-- Returns text used in icon tooltip -----------------------
------------------------------------------------------------
function PKWarning:GetTooltipText()
    
    local text;
    
    if #PKWarning.ZonePKs > 0 then
        text = string.gsub(PKWarning.Lang.Strings["TOOLTIP_PK_NUM"], "<pknum>", #PKWarning.ZonePKs);
        
        local number = 0;
        
        for num, pkInfo in pairs(PKWarning.ZonePKs) do
            number = number + 1;
            text = text .. "\n" .. Sol.color.ColorText(pkInfo["NAME"], PKWarning.Lang.Classes[pkInfo["CLASS_MAIN"]]) .. " " .. pkInfo["LEVEL_MAIN"] .. "/" .. pkInfo["LEVEL_SEC"];
            
            if number >= 5 then
                if #PKWarning.ZonePKs - number > 0 then
                    text = text .. "\n" .. string.gsub(PKWarning.Lang.Strings["TOOLTIP_PK_MORE"], "<pkmore>", (#PKWarning.ZonePKs - number));  
                end
                break;
            end
        end
        
    else
        text = PKWarning.Lang.Strings["TOOLTIP_CLEAN"];
    end
    
    text = text .. Sol.color.ColorText(PKWarning.Lang.Strings["TOOLTIP_MOVE"], "F5B800");
    
    return text;
end

------------------------------------------------------
-- Returns a table of PK's in your zone and channel --
------------------------------------------------------
function PKWarning:UpdateZoneList()

    local myChannel = "" .. GetCurrentParallelID();
    local myZone    = GetZoneName();
    local count     = 0;
    
    PKWarning.ZonePKs = {};

    for pkIndex, pkInfo in pairs(PKWarning.PKs) do
    
        if pkInfo["CHANNEL"] == myChannel then
        
            if pkInfo["ZONE"] == myZone then    
                count = count + 1;
                PKWarning.ZonePKs[count] = pkInfo;
            end
        end 
    end    
    
    PKWarning:UpdateIcon();
end

--------------------------------------------------------------------------------
--- Returns player's world position in normal format ---------------------------
--- Like: 0.654321, 0.41739   --->   65.4, 41.7      ---------------------------
--------------------------------------------------------------------------------
function PKWarning:GetPlayerLocation()

    local x, y = GetPlayerWorldMapPos(); 
    x = math.floor(x * 1000) / 10;
    y = math.floor(y * 1000) / 10;

    return x, y;
end

--------------------------------------------------------------------------------
--- Recounts the PK's in DB based on blacklisted zones     ---------------------
---                                                        ---------------------
--------------------------------------------------------------------------------
function PKWarning:RecountPKs()

    PKWarning.PKCount = 0;

    for pkIndex, pkInfo in pairs(PKWarning.PKs) do
        if not Sol.table.Contains(g_PKWarningBlacklist, pkInfo["ZONE"]) then
            PKWarning.PKCount = PKWarning.PKCount + 1;
        end
    end
    
end
    
--------------------------------------------------------------------------------
--- Initializes a list of PK's                            ---------------------
--------------------------------------------------------------------------------
function PKWarning:InitFrame()

    PKWarning.Frame.NewWarnings = 0;

    PKWarningPanel_Title:SetText(string.gsub(PKWarning.Lang.Strings["PKLIST_TITLE"], "<version>", PKWarning.addon.version));
    PKWarning:InitList();
    PKWarning:UpdateIcon();
end

--------------------------------------------------------------------------------
-- Sorts list of recently seen PKers -------------------------------------------
--------------------------------------------------------------------------------
function PKWarning:SortList()    

    local tempInfo = {};

    -- sort temp table
    local sorted = false;

    while not sorted do
    
        sorted = true; 
        
        for i = 1, #PKWarning.PKs - 1 do
    
            if PKWarning.PKs[i][PKWarning.Frame.Sort] > PKWarning.PKs[i + 1][PKWarning.Frame.Sort] then 
            
                tempInfo = PKWarning.PKs[i + 1];
                PKWarning.PKs[i + 1] = PKWarning.PKs[i];
                PKWarning.PKs[i] = tempInfo;
                
                sorted = false;
            end
        end
    end
end

--------------------------------------------------------------------------------
-- Initializes list of recently seen PKers -------------------------------------
--------------------------------------------------------------------------------
function PKWarning:InitList()    

    PKWarning:InitFilteredList();

    if (#PKWarning.Frame.PKList > PKWarning.Frame.ListMax) then
        PKWarningPanel_ScrollBar:Show();
        PKWarningPanel_ScrollBar:SetMinMaxValues(0, #PKWarning.Frame.PKList - PKWarning.Frame.ListMax);
    else
        PKWarningPanel_ScrollBar:Hide();
        PKWarningPanel_ScrollBar:SetMinMaxValues(0, 0);
        PKWarning.Frame.ScrollValue = 0;
    end

    PKWarning:UpdateList();
end

--------------------------------------------------------------------------------
-- Initializes a list of PK's which are in the DB and matches the selected -----
-- CHANNEL and ZONE, sorted by SORT option                                 -----
--------------------------------------------------------------------------------
function PKWarning:InitFilteredList()

    PKWarning.Frame.PKList = {};
    
    local count = 0;

    for pkIndex, pkInfo in pairs(PKWarning.PKs) do
    
        if PKWarning.Frame.Channel == "-" or pkInfo["CHANNEL"] == PKWarning.Frame.Channel then
        
            if Sol.table.Contains(g_PKWarningBlacklist, pkInfo["ZONE"]) then
        
                -- Blacklisted items
        
            elseif PKWarning.Frame.Zone == "-" or pkInfo["ZONE"] == PKWarning.Frame.Zone then    
                count = count + 1;
                
                PKWarning.Frame.PKList[count] = {};
                PKWarning.Frame.PKList[count]["NAME"]       = pkInfo["NAME"];
                PKWarning.Frame.PKList[count]["CHANNEL"]    = pkInfo["CHANNEL"];
                PKWarning.Frame.PKList[count]["ZONE"]       = pkInfo["ZONE"];
                PKWarning.Frame.PKList[count]["CLASS_MAIN"] = pkInfo["CLASS_MAIN"];
                PKWarning.Frame.PKList[count]["CLASS_SEC"]  = pkInfo["CLASS_SEC"];
                PKWarning.Frame.PKList[count]["LEVELS"]     = pkInfo["LEVEL_MAIN"] .. "/" .. pkInfo["LEVEL_SEC"];
                PKWarning.Frame.PKList[count]["WORLD_X"]    = pkInfo["WORLD_X"];
                PKWarning.Frame.PKList[count]["WORLD_Y"]    = pkInfo["WORLD_Y"]
                PKWarning.Frame.PKList[count]["TIME_SEEN"]  = math.floor(GetTime()) - pkInfo["TIME_SEEN"];
            end
        end 
    end
end

-------------------------------------------------------------------------------
-- Takes filtering (channel, zone) and sorting settings, creates --------------
-- field of PK's and shows it                                       -----------
-------------------------------------------------------------------------------
function PKWarning:UpdateList()

    for i = 1, PKWarning.Frame.ListMax do
  
        local texture  = getglobal("PKWarningPanel_Item" .. i .. "_Texture");
        local name     = getglobal("PKWarningPanel_Item" .. i .. "_Name");
        local channel  = getglobal("PKWarningPanel_Item" .. i .. "_Channel");
        local zone     = getglobal("PKWarningPanel_Item" .. i .. "_Zone");
        local classes  = getglobal("PKWarningPanel_Item" .. i .. "_Classes");
        local levels   = getglobal("PKWarningPanel_Item" .. i .. "_Levels");
        local position = getglobal("PKWarningPanel_Item" .. i .. "_Position");
        local time     = getglobal("PKWarningPanel_Item" .. i .. "_Time");
    
        local pk = PKWarning.Frame.PKList[i + PKWarning.Frame.ScrollValue];
    
        if (pk ~= nil) then
        
            texture:Show();
            
            name:SetText(Sol.color.ColorText(pk["NAME"], PKWarning.Lang.Classes[pk["CLASS_MAIN"]]));
            channel:SetText(pk["CHANNEL"]);
            zone:SetText(pk["ZONE"]);
            classes:SetText(pk["CLASS_MAIN"] .. "/" .. pk["CLASS_SEC"]);
            levels:SetText(pk["LEVELS"]);
            position:SetText(pk["WORLD_X"] .. ", " .. pk["WORLD_Y"]);
            time:SetText(pk["TIME_SEEN"] .. "s ago");
            
            -- Set last seen time and color by threat
            if pk["TIME_SEEN"] < 60 then
                time:SetColor(1, 0, 0);
            elseif pk["TIME_SEEN"] < 120 then
                time:SetColor(1, 0.5, 0);
            elseif pk["TIME_SEEN"] < 240 then
                time:SetColor(1, 1, 0);
            else
                time:SetColor(0, 1, 0);
            end
        
        else
            texture:Hide();
            name:SetText("");
            channel:SetText("");
            zone:SetText("");
            classes:SetText("");
            levels:SetText("");
            position:SetText("");
            time:SetText("");
        end
    end
end

--------------------------------------------------
--- Channel selector -----------------------------
--------------------------------------------------

function PKWarning_ChannelDropDown_OnLoad(this)
    UIDropDownMenu_Initialize(this, PKWarning_ChannelDropDown_Show);
    UIDropDownMenu_SetSelectedID(PKWarningPanel_ChannelDropDown, 1);
end

function PKWarning_ChannelDropDown_Show(this)
    
    local item;
  
    item = {};
    item.text = "-";
    item.arg1 = "-";
    item.func = PKWarning_ChannelDropDown_Click;
    UIDropDownMenu_AddButton(item);
    
    item = {};
    item.text = "1";
    item.arg1 = "1";
    item.func = PKWarning_ChannelDropDown_Click;
    UIDropDownMenu_AddButton(item);
    
    item = {};
    item.text = "2";
    item.arg1 = "2";
    item.func = PKWarning_ChannelDropDown_Click;
    UIDropDownMenu_AddButton(item);
    
    item = {};
    item.text = "3";
    item.arg1 = "3";
    item.func = PKWarning_ChannelDropDown_Click;
    UIDropDownMenu_AddButton(item);
end


function PKWarning_ChannelDropDown_Click(button)
    UIDropDownMenu_SetSelectedID(PKWarningPanel_ChannelDropDown, button:GetID());
    PKWarning.Frame.Channel = button.arg1;
    PKWarning.Frame.ScrollValue = 0;
    PKWarning:InitList();
end

--------------------------------------------------
--- Zone selector --------------------------------
--------------------------------------------------

function PKWarning_ZoneDropDown_OnLoad(this)
    UIDropDownMenu_Initialize(this, PKWarning_ZoneDropDown_Show);
    UIDropDownMenu_SetSelectedID(PKWarningPanel_ZoneDropDown, 1);
    PKWarning.Frame.Zone = "-";
end


function PKWarning_ZoneDropDown_Show(this)
    
    local item;
    local zoneList = {};
    
    -- Get list of zones with PK's --
    for pkIndex, pkInfo in pairs(PKWarning.PKs) do
        if not zoneList[pkInfo["ZONE"]] and not Sol.table.Contains(g_PKWarningBlacklist, pkInfo["ZONE"]) then
            zoneList[pkInfo["ZONE"]] = 1;
        end
    end

    item = {};
    item.text = "-";
    item.arg1 = "-";
    item.func = PKWarning_ZoneDropDown_Click;
    UIDropDownMenu_AddButton(item);
    
    for zoneName, dummy in pairs(zoneList) do
        item = {};
        item.text = zoneName;
        item.arg1 = zoneName;
        item.func = PKWarning_ZoneDropDown_Click;
        UIDropDownMenu_AddButton(item);
    end    
end


function PKWarning_ZoneDropDown_Click(button)
  UIDropDownMenu_SetSelectedID(PKWarningPanel_ZoneDropDown, button:GetID());
  PKWarning.Frame.Zone = button.arg1;
  PKWarning.Frame.ScrollValue = 0;
  PKWarning:InitList();
end

--------------------------------------------------
--- Sort selector -----------------------------
--------------------------------------------------

function PKWarning_SortDropDown_OnLoad(this)
    UIDropDownMenu_Initialize(this, PKWarning_SortDropDown_Show);
    UIDropDownMenu_SetSelectedID(PKWarningPanel_SortDropDown, 1);
end

function PKWarning_SortDropDown_Show(this)
    
    local item;
  
    item = {};
    item.text = "Time";
    item.arg1 = "TIME_SEEN";
    item.func = PKWarning_SortDropDown_Click;
    UIDropDownMenu_AddButton(item);
    
    item = {};
    item.text = "Name";
    item.arg1 = "NAME";
    item.func = PKWarning_SortDropDown_Click;
    UIDropDownMenu_AddButton(item);
    
    item = {};
    item.text = "Class";
    item.arg1 = "CLASS_MAIN";
    item.func = PKWarning_SortDropDown_Click;
    UIDropDownMenu_AddButton(item);
    
    item = {};
    item.text = "Level";
    item.arg1 = "LEVEL_MAIN";
    item.func = PKWarning_SortDropDown_Click;
    UIDropDownMenu_AddButton(item);
    
    item = {};
    item.text = "Zone";
    item.arg1 = "ZONE";
    item.func = PKWarning_SortDropDown_Click;
    UIDropDownMenu_AddButton(item);
    
    item = {};
    item.text = "Channel";
    item.arg1 = "CHANNEL";
    item.func = PKWarning_SortDropDown_Click;
    UIDropDownMenu_AddButton(item);    
end


function PKWarning_SortDropDown_Click(button)
    UIDropDownMenu_SetSelectedID(PKWarningPanel_SortDropDown, button:GetID());
    PKWarning.Frame.Sort = button.arg1;
    PKWarning.Frame.ScrollValue = 0;
    PKWarning:SortList()
    PKWarning:InitList();
end

------------------------------------------------------------
--- Scrollbar - scroll -------------------------------------
------------------------------------------------------------
function PKWarningPanel_ScrollBar_OnValueChanged(this, arg1)
    UIPanelScrollBar_OnValueChanged(this, arg1);
    PKWarning.Frame.ScrollValue = this:GetValue();
    PKWarning:InitList();
end

------------------------------------------------------------
--- Scrollbar - mouse wheel --------------------------------
------------------------------------------------------------
function PKWarningPanel_ScrollBar_OnMouseWheel(this, delta)
  if delta > 0 then
    UIPanelScrollBarTemplate_Scroll(PKWarningPanel_ScrollBar, "UP");
  else
    UIPanelScrollBarTemplate_Scroll(PKWarningPanel_ScrollBar, "DOWN");
  end    
end

--------------------------------------------------------------
------
------ Config functions
------

function PKWarning:Config_OnLoad(this)
end

function PKWarning:Config_OnShow(this)

    PKWarningConfig_Title:SetText("PKWarning config");

    PKWarningConfig_Tab1:SetText("General");
    PKWarningConfig_Tab2:SetText("Blacklist");
    PKWarningConfig_ButtonSaveConfig:SetText("Save");
  
    PKWarningConfig_CheckSendWarningsText:SetText("Send warnings");
    PKWarningConfig_CheckSendPartyWarningsText:SetText("Send warnings about players in you party");
    PKWarningConfig_CheckSendSelfWarningsText:SetText("Send warnings about yourself - for hardcore criminals :)");
    PKWarningConfig_CheckRecieveWarningsText:SetText("Recieve warnings");
    PKWarningConfig_CheckShowZoneWarningsText:SetText("Show warning when entering dangerous zone");
    PKWarningConfig_CheckDisableChatPopupText:SetText("Disable chat messenger popup for PKWarning channel");
    
    PKWarningConfig_CheckSendWarnings:SetChecked(g_PKWarningSettings["ENABLE_SEND"]);
    PKWarningConfig_CheckSendPartyWarnings:SetChecked(g_PKWarningSettings["ENABLE_PARTY"]);
    PKWarningConfig_CheckSendSelfWarnings:SetChecked(g_PKWarningSettings["ENABLE_SELF"]);
    PKWarningConfig_CheckRecieveWarnings:SetChecked(g_PKWarningSettings["ENABLE_RECIEVE"]);
    PKWarningConfig_CheckShowZoneWarnings:SetChecked(g_PKWarningSettings["ENABLE_ZONE_WARNING"]);
    PKWarningConfig_CheckDisableChatPopup:SetChecked(g_PKWarningSettings["DISABLE_CHAT_POPUP"]);
    
    if (#g_PKWarningBlacklist > PKWarning.Config.BlacklistMax) then
        PKWarningConfig_ScrollBar:Show();
        PKWarningConfig_ScrollBar:SetMinMaxValues(0, #g_PKWarningBlacklist - PKWarning.Config.BlacklistMax);
    else
        PKWarningConfig_ScrollBar:Hide();
        PKWarningConfig_ScrollBar:SetMinMaxValues(0, 0);
        PKWarning.Config.ScrollValue = 0;
    end

    PKWarning:Blacklist_Init();
    PKWarning:Config_OnTabClick(1);
end

function PKWarning:Config_OnTabClick(tabID)

  if tabID == 1 then
      PKWarningConfig_TabOptions:Show();
      PKWarningConfig_TabBlacklist:Hide();
  elseif tabID == 2 then
      PKWarningConfig_TabOptions:Hide();
      PKWarningConfig_TabBlacklist:Show();
  end
end

function PKWarning:Config_Save()
    g_PKWarningSettings["ENABLE_SEND"]          = PKWarningConfig_CheckSendWarnings:IsChecked();
    g_PKWarningSettings["ENABLE_PARTY"]         = PKWarningConfig_CheckSendPartyWarnings:IsChecked();
    g_PKWarningSettings["ENABLE_SELF"]          = PKWarningConfig_CheckSendSelfWarnings:IsChecked();
    g_PKWarningSettings["ENABLE_RECIEVE"]       = PKWarningConfig_CheckRecieveWarnings:IsChecked();
    g_PKWarningSettings["ENABLE_ZONE_WARNING"]  = PKWarningConfig_CheckShowZoneWarnings:IsChecked();
    g_PKWarningSettings["DISABLE_CHAT_POPUP"]   = PKWarningConfig_CheckDisableChatPopup:IsChecked();
    
    MSN_INFO["CHANNEL"].auto = not g_PKWarningSettings["DISABLE_CHAT_POPUP"];
    CRG_SetAutoCheck(6, not g_PKWarningSettings["DISABLE_CHAT_POPUP"]);
    
    SaveVariables("g_PKWarningSettings");
    SaveVariables("g_PKWarningBlacklist");
    
    GC_Save();
end

----- Add current zone to blacklist
function PKWarning:Blacklist_Add()

    if PKWarning.Frame.Zone ~= "-" then
        if not Sol.table.Contains(g_PKWarningBlacklist, PKWarning.Frame.Zone) then
            table.insert(g_PKWarningBlacklist, PKWarning.Frame.Zone);
            PKWarning_ZoneDropDown_OnLoad(PKWarningPanel_ZoneDropDown);
            PKWarning:RecountPKs();
            PKWarning:InitList();
            PKWarning:UpdateIcon();
        end
    end
end

------ Remove zone from blacklist
function PKWarning:Blacklist_Delete(id)
    table.remove(g_PKWarningBlacklist, id + PKWarning.Config.ScrollValue);
    PKWarning:Config_OnShow();
    PKWarning_ZoneDropDown_OnLoad(PKWarningPanel_ZoneDropDown);
    PKWarning:RecountPKs();
    PKWarning:InitList();
    PKWarning:UpdateIcon();
end

function PKWarning:Blacklist_Init()
    for i = 1, PKWarning.Config.BlacklistMax do
  
        local texture  = getglobal("PKWarningConfig_BlacklistItem" .. i .. "_Texture");
        local name     = getglobal("PKWarningConfig_BlacklistItem" .. i .. "_ZoneName");
        local button   = getglobal("PKWarningConfig_BlacklistItem" .. i .. "_DeleteButton");
    
        local zone = g_PKWarningBlacklist[i + PKWarning.Config.ScrollValue];
    
        if (zone ~= nil) then
        
            texture:Show();
            button:Show();
            button:SetText("X");
            name:SetText(zone);
        else
            texture:Hide();
            button:Hide();
            name:SetText("");
        end
    end
end

------------------------------------------------------------
--- Scrollbar - scroll -------------------------------------
------------------------------------------------------------
function PKWarningConfig_Blacklist_OnValueChanged(this, arg1)
    UIPanelScrollBar_OnValueChanged(this, arg1);
    PKWarning.Config.ScrollValue = this:GetValue();
    PKWarning:Blacklist_Init();
end

function PKWarningConfig_Toggle()
  
    if PKWarningConfig:IsVisible() then
        PKWarningConfig:Hide();
    else
        PKWarningConfig:Show();
    end;
end;
